#include <QCoreApplication>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <QtDebug>
/*
 * 文件头
 */
typedef struct ShpHeadCharData{
    char fileCode[4];
    char unused[20];
    char fileLength[4];

}ShpHeadCharData ;

/*
 * 点数据
 */
typedef struct ShpPointData {
    char recordNumber[4];
    char contentLength[4];
    int shapeType;
} ShpPointData;

/*
 * 线数据
 */
typedef struct ShpPolyLineData {
    char recordNumber[4];
    char contentLength[4];
    int shapeType;
    char box1[8];
    char box2[8];
    char box3[8];
    char box4[8];
    int numParts;
    int numPoints;
} ShpPolyLineData;

/*
 * 文件头数据
 */
typedef struct ShxHeadData{
    int fileCode;
    int unused;
    int fileLength;
    int version;
    int shapeType;
    double xmin;
    double ymin;
    double xmax;
    double ymax;
    double zmin;
    double zmax;
    double mmin;
    double mmax;
}ShxHeadData ;

/*
 * 文件头数据
 */
typedef struct ShxHeadInfoData{
    int version;
    int shapeType;
    double xmin;
    double ymin;
    double xmax;
    double ymax;
    double zmin;
    double zmax;
    double mmin;
    double mmax;
}ShxHeadInfoData ;


char* toLittleData(char* tem, int size) {
    char* tema = new char[size];
    int index = 0;
    for (int i = size - 1; i >= 0; i--) {
        tema[index++] = tem[i];
    }
    return tema;
}

char* toData(char* tem) {
    return tem;
}

typedef struct DbfHeadInfoData {
    char version;
    char update[3];
    uint32_t recordNum;
    uint16_t headerByteNum;
    uint16_t recordByteNum;
    uint16_t reserved1;
    char noOpt;
    char dbaseIv;
    char userOpts[12];
    char mdxFlag;
    char languageDriverId;
    uint16_t reserved2;
}DbfHeadInfoData ;

typedef struct DbfDataType {
    char name[11];
    char fieldType;
    uint32_t reserved3;
    char fieldLength;
    char decimalCount;
    uint16_t reserved4;
    char workId;
    char reserved5[10];
//    uint16_t reserved51;
//    uint16_t reserved52;
//    uint16_t reserved53;
//    uint16_t reserved54;
//    uint16_t reserved55;
    char mdxFlag;
} DbfDataType;



/**
 * @brief readShp  读取Shp文件
 * @param file  文件流
 * @return
 */
int readShp(FILE *file){
    //读取SHP File
    //读取SHP\SHX File头
    ShpHeadCharData *head = new ShpHeadCharData();
    fread(head,sizeof(ShpHeadCharData),1,file);
    ShxHeadData *headData = new ShxHeadData();
    headData->fileCode = *(int*)toLittleData(head->fileCode,4);
    headData->fileLength = *(int*)toLittleData(head->fileLength,4);
    ShxHeadInfoData *headInfo = new ShxHeadInfoData();
    fread(headInfo,sizeof(ShxHeadInfoData),1,file);
    std::cout << "FileCode="<<headData->fileCode <<std::endl;
    std::cout << "unused="<<headData->unused <<std::endl;
    std::cout << "fileLength="<<headData->fileLength <<std::endl;
    std::cout << "version="<<headInfo->version <<std::endl;
    std::cout << "shapeType="<<headInfo->shapeType <<std::endl;
    std::cout << "xmin="<<headInfo->xmin <<std::endl;
    std::cout << "ymin="<<headInfo->ymin <<std::endl;
    std::cout << "xmax="<<headInfo->xmax <<std::endl;
    std::cout << "ymax="<<headInfo->ymax <<std::endl;
    std::cout << "zmin="<<headInfo->zmin <<std::endl;
    std::cout << "zmax="<<headInfo->zmax <<std::endl;
    std::cout << "mmin="<<headInfo->mmin <<std::endl;
    std::cout << "mmax="<<headInfo->mmax <<std::endl;

    if(headInfo->shapeType == 1) {
       ShpPointData *point = new ShpPointData();
       while((fread(point,sizeof(ShpPointData),1,file))){
           double pointsX;
           double pointsY;
           fread(&pointsX,sizeof(double),1,file);
           fread(&pointsY,sizeof(double),1,file);
           std::cout << "shapeType=" << point->shapeType << "recordNumber=" << *(int*)toLittleData(point->recordNumber,4) << "contentLength=" << *(int*)toLittleData(point->contentLength,4)  << "PointX=" << pointsX << "   PointY=" << pointsY << std::endl;
       }
    }else if(headInfo->shapeType == 3){
        ShpPolyLineData *polyLine = new ShpPolyLineData();
        while((fread(polyLine,sizeof(ShpPolyLineData),1,file))){
            std::cout << "Box:" << *(double*)polyLine->box1 << " " <<*(double*)polyLine->box2 << " " <<*(double*)polyLine->box3 << " " <<*(double*)polyLine->box4 << " " << std::endl;
            std::cout << "recordNumber=" << polyLine->recordNumber << "contentLength=" << polyLine->contentLength << "shapeType=" << polyLine->shapeType << "  numParts=" << polyLine->numParts << "  numPoints=" << polyLine->numPoints << std::endl;
            int *parts = new int[polyLine->numParts];
            for(int i=0;i<polyLine->numParts;i++){
                fread(parts+i,sizeof(int),1,file);
            }
            int pointNum;
            for(int i=0;i<polyLine->numParts;i++){
                if(i!=(polyLine->numParts-1)){
                    pointNum = parts[i+1]-parts[i];
                }else{
                    pointNum = polyLine->numPoints - parts[i];
                }
                std::cout << "PointNum=" << pointNum << std::endl;
                double *pointsX = new double[pointNum];
                double *pointsY = new double[pointNum];
                for(int j=0;j<pointNum;j++){
                    fread(pointsX+j,sizeof(double),1,file);
                    fread(pointsY+j,sizeof(double),1,file);

                    std::cout << "PointX=" << pointsX[j] << "   PointY=" << pointsY[j] << std::endl;
                }

            }

        }
    }else if(headInfo->shapeType == 5){
        ShpPolyLineData *polyLine = new ShpPolyLineData();
        while((fread(polyLine,sizeof(ShpPolyLineData),1,file))){
            std::cout << "Box:" << *(double*)polyLine->box1 << " " <<*(double*)polyLine->box2 << " " <<*(double*)polyLine->box3 << " " <<*(double*)polyLine->box4 << " " << std::endl;
            std::cout << "recordNumber=" << polyLine->recordNumber << "contentLength=" << polyLine->contentLength << "shapeType=" << polyLine->shapeType << "  numParts=" << polyLine->numParts << "  numPoints=" << polyLine->numPoints << std::endl;
            int *parts = new int[polyLine->numParts];
            for(int i=0;i<polyLine->numParts;i++){
                fread(parts+i,sizeof(int),1,file);
            }
            int pointNum;
            for(int i=0;i<polyLine->numParts;i++){
                if(i!=(polyLine->numParts-1)){
                    pointNum = parts[i+1]-parts[i];
                }else{
                    pointNum = polyLine->numPoints - parts[i];
                }
                std::cout << "PointNum=" << pointNum << std::endl;
                double *pointsX = new double[pointNum];
                double *pointsY = new double[pointNum];
                for(int j=0;j<pointNum;j++){
                    fread(pointsX+j,sizeof(double),1,file);
                    fread(pointsY+j,sizeof(double),1,file);

                    std::cout << "PointX=" << pointsX[j] << "   PointY=" << pointsY[j] << std::endl;
                }

            }

        }
    }
//     fclose(file);

    return 1;
}

/**
 * @brief readDbf  读取数据
 * @param file
 * @return
 */
int readDbf(FILE *file) {
    //读取DBF File头
    DbfHeadInfoData *dbHead = new DbfHeadInfoData();
    fread(dbHead,sizeof(DbfHeadInfoData),1,file);
    std::cout << "version="<<(int)dbHead->version <<std::endl;
    std::cout << "LastUpdate="<<(int)dbHead->update[0] << "-" << (int)dbHead->update[1] << "-" << (int)dbHead->update[2] <<std::endl;
    std::cout << "recordNum="<<dbHead->recordNum <<std::endl;
    std::cout << "byeNum="<<dbHead->headerByteNum <<std::endl;
    std::cout << "logByeNum="<<dbHead->recordByteNum <<std::endl;

    std::cout << "noOpt="<<dbHead->reserved1 <<std::endl;
    std::cout << "dbaseIv="<<dbHead->dbaseIv <<std::endl;
    std::cout << "mdxFlag="<<dbHead->mdxFlag <<std::endl;
    std::cout << "languageDriverId="<<dbHead->languageDriverId <<std::endl;
    std::cout << "Reserved1="<< dbHead->reserved1 <<std::endl;
    std::cout << "reserved2="<<dbHead->reserved2 <<std::endl;

    int fieldsCount = (dbHead->headerByteNum - 32) /32;
    DbfDataType *cols[fieldsCount];
    for(int i=0;i<fieldsCount;i++){
        DbfDataType *data = new DbfDataType();
        fread(data,sizeof(DbfDataType),1,file);
        cols[i] = data;
        std::cout << "Name="<<data->name << " Type= "<< data->fieldType << " Length= " << (int)(unsigned char)data->fieldLength << " Precision= " << (int)(unsigned char)data->decimalCount << std::endl;
    }

    char terminator;
    fread(&terminator,sizeof(char),1,file);
    std::cout << "terminator=" << (int)terminator << std::endl;
    char deleteFlag;

    for(int i=0;i<dbHead->recordNum;i++){
        fread(&deleteFlag,sizeof(char),1,file);
        for(int j=0;j<fieldsCount;j++){
            int fl = (int)(unsigned char)cols[j]->fieldLength ;
            char *value =  (char*)malloc(fl);
            for(int k=0;k<fl;k++){
                 strcpy(value+k,"");
            }
            fread(value,fl*sizeof(char),1,file);

            if(cols[j]->fieldType == 'B'){
                std::cout << cols[j]->name << " = B " <<value << "   ";
            }else if(cols[j]->fieldType == 'C'){
                std::cout << cols[j]->name << " = C " <<value << "   ";
            }else if(cols[j]->fieldType == 'D'){
                std::cout << cols[j]->name << " = D " << value << "   ";
            }else if(cols[j]->fieldType == 'F'){
                std::cout << cols[j]->name << " = F " << atof(value) << "   ";
            }else if(cols[j]->fieldType == 'G'){
                std::cout << cols[j]->name << " = G " << value << "   ";
            }else if(cols[j]->fieldType == 'N'){
                std::cout << cols[j]->name << " = N " << atoi(value) << "   ";
            }else if(cols[j]->fieldType == 'L'){
                std::cout << cols[j]->name << " = L " << value << "   ";
            }else if(cols[j]->fieldType == 'M'){
                std::cout << cols[j]->name << " = M " << value << "   ";
            }else{
                 std::cout << cols[j]->name << " = W " << value << "   ";
            }
        }
        std::cout <<""<<std::endl;
    }

//    fclose(file);

    return 1;
}

/**
 * @brief readShx 读取索引文件
 * @param file
 * @return
 */
int readShx(FILE *file){
    //读取SHP\SHX File头

    ShpHeadCharData *head = new ShpHeadCharData();
    fread(head,sizeof(ShpHeadCharData),1,file);
    ShxHeadData *headData = new ShxHeadData();
    headData->fileCode = *(int*)toLittleData(head->fileCode,4);
    headData->fileLength = *(int*)toLittleData(head->fileLength,4);
    ShxHeadInfoData *headInfo = new ShxHeadInfoData();
    fread(headInfo,sizeof(ShxHeadInfoData),1,file);
    std::cout << "FileCode="<<headData->fileCode <<std::endl;
    std::cout << "unused="<<headData->unused <<std::endl;
    std::cout << "fileLength="<<headData->fileLength <<std::endl;
    std::cout << "version="<<headInfo->version <<std::endl;
    std::cout << "shapeType="<<headInfo->shapeType <<std::endl;
    std::cout << "xmin="<<headInfo->xmin <<std::endl;
    std::cout << "ymin="<<headInfo->ymin <<std::endl;
    std::cout << "xmax="<<headInfo->xmax <<std::endl;
    std::cout << "ymax="<<headInfo->ymax <<std::endl;
    std::cout << "zmin="<<headInfo->zmin <<std::endl;
    std::cout << "zmax="<<headInfo->zmax <<std::endl;
    std::cout << "mmin="<<headInfo->mmin <<std::endl;
    std::cout << "mmax="<<headInfo->mmax <<std::endl;

    //读取SHX File数据
    char offset[4];
    char contentLength[4];
    while(fread(offset,4,1,file)){
        fread(contentLength,4,1,file);
        std::cout << "Offset=" << *(int*)toLittleData(offset,4) << "ContentLength=" << *(int*)toLittleData(offset,4) << std::endl;
    }

//    fclose(file);


 return 1;
//    delete  head;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //     fseek(file, sizeof(ShpHeadCharData), SEEK_SET);

    std::cout << "hello word!" << std::endl;
    QString rootPath = QCoreApplication::applicationDirPath()+"/Test/hq/hq.shp";
    char *filePath = rootPath.toLocal8Bit().data();
    std::cout << filePath << std::endl;
    FILE *fileShp = fopen(filePath,"rb");
    if(fileShp == NULL){
        std::cout << " File读取失败1" << std::endl;
        return a.exec();
    }

    std::cout << "Start Read SPH File" <<std::endl;
    readShp(fileShp);
    std::cout << "End Read SHP File" <<std::endl;

    QString dbfPath = rootPath.replace(".shp",".dbf");
    char *fileDbfPath = dbfPath.toLocal8Bit().data();
//    std::cout << filePath << std::endl;
    FILE *fileDbf = fopen(fileDbfPath,"rb");

    std::cout << "Start Read DBF File" <<std::endl;
    readDbf(fileDbf);
    std::cout << "End Read DBF File" <<std::endl;

    QString spxPath = rootPath.replace(".dbf",".spx");
    char *fileSpxPath = spxPath.toLocal8Bit().data();
//    std::cout << filePath << std::endl;
    FILE *fileSpx = fopen(fileSpxPath,"rb");


    std::cout << "Start Read SPX File" <<std::endl;
    readShx(fileSpx);
    std::cout << "End Read SHX File" <<std::endl;


   fclose(fileShp);
   fclose(fileDbf);
   fclose(fileSpx);

    return a.exec();
}
